package com.changpeng.shake.aspect;


import com.alibaba.fastjson.JSON;
import com.changpeng.shake.annotation.NoRepeatSubmit;
import com.changpeng.shake.common.RequestKeyGenerator;
import com.changpeng.shake.common.enums.ResultEnum;
import com.changpeng.shake.common.exception.VerificationException;
import com.changpeng.shake.common.utils.RedisUtil;
import com.changpeng.shake.common.utils.RepeatSubmitUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.util.StringUtils;

import java.lang.reflect.Method;

@Aspect
@Configuration
@Order(2)
public class RedissonRequestLockAspect {
    private static final Logger logger = LoggerFactory.getLogger(RedissonRequestLockAspect.class);
    @Autowired
    private RedisUtil redisUtil;


    @Pointcut("@annotation(com.changpeng.shake.annotation.NoRepeatSubmit)")
    public void serviceNoRepeat() {
    }

    @Around("serviceNoRepeat()")
    public Object interceptor(ProceedingJoinPoint joinPoint) throws Throwable {
        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        Method method = methodSignature.getMethod();
        NoRepeatSubmit requestLock = method.getAnnotation(NoRepeatSubmit.class);
        if (StringUtils.isEmpty(requestLock.prefix())) {
            throw new VerificationException(ResultEnum.FAIL, "重复提交前缀不能为空");
        }
        //todo 正式环境请加上用户ID和IP属地，减少误判
        //获取自定义key
        final String lockKey = RequestKeyGenerator.getLockKey(joinPoint);
        // 使用Redisson分布式锁的方式判断是否重复提交
//        Long userId = getCurrentUser().getId();
        Long userId = 12345L;
        String methodName = joinPoint.getSignature().getDeclaringTypeName() + "#" + joinPoint.getSignature().getName();
        String key = "repeat:U=" + userId + "M=" + methodName + "P=" + lockKey;

        // expireTime毫秒过期，expireTime ms内的重复请求会认为重复
        long expireTime = requestLock.expire();
        long expireAt = System.currentTimeMillis() + expireTime;
        String val = "expireAt@" + expireAt;

        if (redisUtil.setNX(key, val, expireTime)) {
            logger.info("第一次提交[{}]", method);
            return joinPoint.proceed();
        } else {
            logger.info("重复提交[{}]", method);
            throw new VerificationException(ResultEnum.FAIL, "请不要频繁提交相同请求");
        }

    }


}
